package com.lagou.edu.utils;

import com.lagou.edu.factory.ProxyFactory;
import com.lagou.edu.factory.ProxyFactoryM;
import org.junit.Test;

import java.io.File;
import java.io.FileFilter;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class ApplicationContext {
    //包名
    private String packageName;
    private ConcurrentHashMap<String,Object> beans=new ConcurrentHashMap<>();

    public ApplicationContext(String packageName){
        this.packageName=packageName;
        initBeans();
    }
    private void initBeans(){
        List<Class> classList=getClasses(packageName);
        findClassIsAddedCostomAnnotation(classList);

        for(Map.Entry<String,Object> map:beans.entrySet()){
            System.out.println(map.getKey()+"===="+map.getValue());
        }
    }
//获取加了注解的class文件
    private List<Class> getClasses(String packageName){
        List<Class> classList=new ArrayList<>();
        String packageDirName=packageName.replace(".","/");
        System.out.println("packageName:"+packageDirName);
        Enumeration<URL> dirs;
        try{
            dirs=Thread.currentThread().getContextClassLoader().getResources(packageDirName);
            while(dirs.hasMoreElements()){
                URL url=dirs.nextElement();
                String protol=url.getProtocol();
                if(protol.equals("file")){
                    String filePath= URLDecoder.decode(url.getFile(),"UTF-8");
                    findAndAddClassesInPackageByFile(packageName,filePath,classList);

                }
            }
        }catch (Exception e){
                e.printStackTrace();
        }
        return classList;
    }
    //在文件中找到
    private void findAndAddClassesInPackageByFile(String packageName,String filePath,List<Class> classList ){
        File dir=new File(filePath);
        File[] files=dir.listFiles(new FileFilter() {
            @Override
            public boolean accept(File file) {
                return (file.isDirectory()||file.getName().endsWith(".class"));
            }
        });
        for (File file : files) {
            if(file.isDirectory()){
                findAndAddClassesInPackageByFile(packageName+"."+file.getName(),file.getAbsolutePath(),classList);
            }else{
                String className=file.getName().substring(0,file.getName().length()-6);
//                System.out.print(className);
                try {
                    classList.add(Class.forName(packageName+"."+className));
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    //找到加了注解的class
    private void findClassIsAddedCostomAnnotation(List<Class> classList){
        for (Class aClass : classList) {
            classToObjectIntoBeans(aClass,classList);
        }
//        for (Class aClass : classList) {
//            System.out.println(aClass.getName()+"-----");
//        }
    }
//把class转换成bean
    private void classToObjectIntoBeans(Class aClass,List<Class>  classList) {
        Object obj = null;
        try {
            if(aClass.isInterface()){
                for(Class implClass : classList) {
                    if (implClass.isInterface()) {
                        continue;
                    }
                    Class fieldClassCopy = implClass.getClassLoader().loadClass(aClass.getName());
                    if (fieldClassCopy.isAssignableFrom(implClass)) {
                        Constructor[] constructors = implClass.getConstructors();
                        for(Constructor constructor : constructors){
                            int parameterCount = constructor.getParameterCount();
                            if(parameterCount==0){
                                obj = constructor.newInstance();
                            }
                        }
                        break;
                    }
                }
            } else {
                Constructor[] constructors = aClass.getConstructors();
                for(Constructor constructor : constructors){
                    int parameterCount = constructor.getParameterCount();
                    if(parameterCount==0){
                        obj = constructor.newInstance();
                    }
                }
            }
            if (obj != null) {
                beans.put(aClass.getSimpleName(), obj);
            }

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
//提供对外接口
    public Object getBean(String beanName,ApplicationContext applicationContext){
//            System.out.print(beans.size()+"=====================================================");
//            for(Map.Entry<String,Object> map:beans.entrySet()){
//                System.out.println(map.getKey()+"==================="+map.getValue());
//            }
            Object beanObject=beans.get(beanName);
            try{
                referenceBindObject(beanObject);
            }catch (Exception e){
                e.printStackTrace();
            }
            Class aclass=beanObject.getClass();
        Annotation annotation= aclass.getAnnotation(Transactional.class);
        if(null!=annotation){
            ProxyFactoryM proxyFactoryM= (ProxyFactoryM) applicationContext.getBean("ProxyFactoryM",applicationContext);
            beanObject=proxyFactoryM.getJDKProxy(beanObject);
        }
        return beanObject;
    }
    //转换

    private Object referenceBindObject(Object beanObject){
        try {
            Class beanClass=beanObject.getClass();
            Field[] declaredFields=beanClass.getDeclaredFields();
        for (Field declaredField : declaredFields) {
                if(!declaredField.isAccessible()){
                    declaredField.setAccessible(true);
                }
                Autowired autowired=declaredField.getAnnotation(Autowired.class);
                if(autowired==null){
                    System.out.println(beanClass.getName()+"类"+declaredField.getName()+"字段上没有注解");
                    break;
                }

                Class fieldClass=declaredField.getType();
                String classSimpleName=fieldClass.getSimpleName();
                Object fieldObject=beans.get(classSimpleName);
                Object object=referenceBindObject(fieldObject);

                declaredField.set(beanObject,object);
            }
        }catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return beanObject;
    }
}
